package model

import (
	"bytes"
	"common/helper"
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/shopspring/decimal"
	"github.com/valyala/fasthttp"
	"io/ioutil"
	"member/contrib/validator"
	"net/http"
	"net/url"
	"sort"
	"strconv"
	"strings"
	"time"
)

type thirdEpay struct {
}

//type EpayCallBack struct {
//	MchId      int    `json:"mch_id"`
//	Code       int    `json:"code"`
//	OrderNo    string `json:"order_no"`
//	DisOrderNo string `json:"dis_order_no"`
//	OrderPrice int    `json:"order_price"`
//	RealPrice  int    `json:"real_price"`
//	OrderCost  int    `json:"order_cost"`
//	NtiTime    int    `json:"nti_time"`
//	Sign       string `json:"sign"`
//}

type BetcatCallBack struct {
	Sign        string `json:"sign"`
	Amount      string `json:"amount"`
	Attach      string `json:"attach"`
	OrderNo     string `json:"orderNo"`
	Currency    string `json:"currency"`
	CreateTime  string `json:"createTime"`
	MerOrderNo  string `json:"merOrderNo"`
	UpdateTime  string `json:"updateTime"`
	OrderStatus string `json:"orderStatus"`
}

type Pay4zCallBack struct {
	MerchantNo     string `json:"merchantNo"`
	MrchantOrderNo string `json:"merchantOrderNo"`
	OrderNo        string `json:"orderNo"`
	Amount         string `json:"amount"`
	UpdateTime     string `json:"updateTime"`
	OrderStatus    string `json:"orderStatus"`
}

type PayU2CCallBack struct {
	MerchantNo     string `json:"merchantNo"`
	MrchantOrderNo string `json:"merchantOrderNo"`
	OrderNo        string `json:"orderNo"`
	Amount         string `json:"amount"`
	UpdateTime     string `json:"updateTime"`
	OrderStatus    string `json:"orderStatus"`
}

type EpayCallBack struct {
	AppId           string `json:"appId"`
	CustId          string `json:"custId"`
	MerchantOrderId string `json:"merchantOrderId"`
	Order           string `json:"order"`
	OrderStatus     string `json:"orderStatus"`
	Amount          string `json:"amount"`
	OrderTime       string `json:"orderTime"`
	PayAmt          string `json:"payAmt"`
	Sign            string `json:"sign"`
}

type EpayWithdrawCallBack struct {
	OrderNo    string `json:"order_no"`
	MchOrderNo string `json:"mch_order_no"`
	Amount     int64  `json:"amount"`
	Status     int    `json:"status"`
	Fee        int    `json:"fee"`
	Sign       string `json:"sign"`
}

type depositResp struct {
	PayType         string `json:"payType"`
	PayContent      string `json:"payContent"`
	Order           string `json:"order"`
	MerchantOrderId string `json:"merchantOrderId"`
	Code            string `json:"code"`
	Msg             string `json:"msg"`
	ContentType     string `json:"contentType"`
	Sign            string `json:"sign"`
}

type withdrawResp struct {
	Code            string `json:"code"`
	Msg             string `json:"msg"`
	OrdStatus       string `json:"ordStatus"`
	MerchantOrderId string `json:"merchantOrderId"`
	Amount          string `json:"amount"`
	Time            string `json:"time"`
	Order           string `json:"order"`
	Sign            string `json:"sign"`
}

func (that *thirdEpay) DepositCallBack(fctx *fasthttp.RequestCtx) (EpayCallBack, error) {

	params := EpayCallBack{}
	params.AppId = string(fctx.FormValue("appId"))
	params.CustId = string(fctx.FormValue("custId"))
	params.MerchantOrderId = string(fctx.FormValue("merchantOrderId"))
	params.Order = string(fctx.FormValue("order"))
	params.OrderStatus = string(fctx.FormValue("orderStatus"))
	params.Amount = string(fctx.FormValue("amount"))
	params.OrderTime = string(fctx.FormValue("orderTime"))
	params.PayAmt = string(fctx.FormValue("amount"))
	params.Sign = string(fctx.FormValue("sign"))
	return params, nil
}

func (that *thirdEpay) DepositJeepayCallBack(fctx *fasthttp.RequestCtx) (EpayCallBack, error) {
	params := EpayCallBack{}
	var postData = map[string]interface{}{}
	err := json.Unmarshal(fctx.PostBody(), &postData)
	if err != nil {
		return params, err
	}
	orderId := postData["mchOrderNo"].(string)
	query := "select * from tbl_deposit where id=" + orderId
	order := TblDeposit{}
	err = meta.MerchantDB.Get(&order, query)
	if err != nil {
		return params, err
	}
	if order.State == DepositSuccess || order.State == DepositCancelled || order.State == DepositRepairSuccess {
		err = fmt.Errorf("duplicated deposite notify: [%d]", order.State)
		helper.InfoLog("[DepositCallBack:order.State]:%s", err.Error())
		fctx.SetBody([]byte(`success`))
		return params, err
	}
	params.Amount = postData["amount"].(string)
	err = compareAmount(params.Amount, order.Amount, 100)
	if err != nil {
		helper.InfoLog("compare amount error: [err: %v, req: %s, origin: %s]", err, params.Amount, order.Amount)
		helper.InfoLog("[DepositCallBack:compareAmount]:%s", err.Error())
		fctx.SetBody([]byte(`failed`))
		return params, err
	}

	keyy := ""
	query = "select app_key from tbl_pay_factory where fid=" + order.Fid
	err = meta.MerchantDB.Get(&keyy, query)
	if err != nil {
		return params, err
	}

	content := JeepaySign(postData, keyy, "sign")
	sign := strings.ToUpper(helper.MD5Hash(content))
	oldSign := postData["sign"].(string)
	if oldSign != sign {
		fmt.Printf("old sign=%s, new state=%s", oldSign, sign)
		helper.InfoLog("%s订单号签名不对, old sign=%s, new state=%s, content=%s ", orderId, oldSign, sign, content)
		return params, errors.New(helper.SignValidErr)
	}
	params.OrderStatus = postData["state"].(string)
	params.MerchantOrderId = orderId

	return params, nil
}

func (that *thirdEpay) DepositBetcatCallBack(fctx *fasthttp.RequestCtx) (BetcatCallBack, error) {
	params := BetcatCallBack{}
	var postData = map[string]interface{}{}
	err := json.Unmarshal(fctx.PostBody(), &postData)
	if err != nil {
		return params, err
	}
	orderId := postData["merOrderNo"].(string)
	//query := "select * from tbl_deposit where id=" + orderId
	query := fmt.Sprintf("select * from tbl_deposit where id='%s'", orderId)
	order := TblDeposit{}
	err = meta.MerchantDB.Get(&order, query)
	if err != nil {
		return params, err
	}
	if order.State == DepositSuccess || order.State == DepositCancelled || order.State == DepositRepairSuccess {
		err = fmt.Errorf("duplicated deposite notify: [%d]", order.State)
		helper.InfoLog("[DepositCallBack:order.State]:%s", err.Error())
		fctx.SetBody([]byte(`success`))
		return params, err
	}

	aaaa := postData["amount"].(float64)

	params.Amount = fmt.Sprintf("%f", aaaa)
	err = compareAmount(params.Amount, order.Amount, 1)
	if err != nil {
		helper.InfoLog("compare amount error: [err: %v, req: %s, origin: %s]", err, params.Amount, order.Amount)
		helper.InfoLog("[DepositCallBack:compareAmount]:%s", err.Error())
		fctx.SetBody([]byte(`failed`))
		return params, err
	}

	keyy := ""
	query = "select app_key from tbl_pay_factory where fid=" + order.Fid
	err = meta.MerchantDB.Get(&keyy, query)
	if err != nil {
		return params, err
	}

	//	delete(postData, "attach")
	//	delete(postData, "real_cpf")
	//	delete(postData, "end_id")
	content := JeepaySign(postData, keyy, "sign")

	byteData := []byte(content)
	// Step 2: SHA256 编码
	hash := sha256.Sum256(byteData)
	// Step 3: 转成 16 进制字符串
	sign := hex.EncodeToString(hash[:])

	oldSign := postData["sign"].(string)
	if oldSign != sign {
		fmt.Printf("old sign=%s, new state=%s", oldSign, sign)
		helper.InfoLog("%s订单号签名不对, old sign=%s, new state=%s, content=%s ", orderId, oldSign, sign, content)
		return params, errors.New(helper.SignValidErr)
	}

	if returnCode, ok := postData["orderStatus"].(float64); ok {
		//params.OrderStatus = strconv.Itoa(returnCode)
		params.OrderStatus = fmt.Sprintf("%.f", returnCode)
	}
	params.MerOrderNo = orderId

	return params, nil
}

func (that *thirdEpay) DepositPayu2cCallBack(fctx *fasthttp.RequestCtx) (PayU2CCallBack, error) {
	params := PayU2CCallBack{}

	postData := map[string]interface{}{
		"merchantId":      string(fctx.FormValue("merchantId")),
		"merchantOrderNo": string(fctx.FormValue("merchantOrderNo")),
		"orderNo":         string(fctx.FormValue("orderNo")),
		"amount":          string(fctx.FormValue("amount")),
		"status":          string(fctx.FormValue("status")),
		"currency":        string(fctx.FormValue("currency")),
		"payType":         string(fctx.FormValue("payType")),
		"sign":            string(fctx.FormValue("sign")),
	}

	orderId := postData["merchantOrderNo"].(string)
	//query := "select * from tbl_deposit where id=" + orderId
	query := fmt.Sprintf("select * from tbl_deposit where id='%s'", orderId)
	order := TblDeposit{}
	err := meta.MerchantDB.Get(&order, query)
	if err != nil {
		return params, err
	}
	if order.State == DepositSuccess || order.State == DepositCancelled || order.State == DepositRepairSuccess {
		err = fmt.Errorf("duplicated deposite notify: [%d]", order.State)
		helper.InfoLog("[DepositPayu2cCallBack:order.State]:%s", err.Error())
		fctx.SetBody([]byte(`success`))
		return params, err
	}

	strAmount := postData["amount"].(string)

	aaaa, err1 := strconv.ParseFloat(strAmount, 64)
	if err1 != nil {
		helper.InfoLog("[DepositPayu2cCallBack:order.State]:%s", err.Error())
		return params, err1
	}
	params.Amount = fmt.Sprintf("%f", aaaa/100)
	err = compareAmount(params.Amount, order.Amount, 1)
	if err != nil {
		helper.InfoLog("compare amount error: [err: %v, req: %s, origin: %s]", err, params.Amount, order.Amount)
		helper.InfoLog("[DepositPayu2cCallBack:compareAmount]:%s", err.Error())
		fctx.SetBody([]byte(`failed`))
		return params, err
	}

	keyy := ""
	query = "select app_key from tbl_pay_factory where fid=" + order.Fid
	err = meta.MerchantDB.Get(&keyy, query)
	if err != nil {
		return params, err
	}

	//	delete(postData, "attach")
	//	delete(postData, "real_cpf")
	//	delete(postData, "end_id")
	content := PayU2CSign(postData, keyy, "sign")

	// 进行 MD5 运算并转换为小写
	sign := strings.ToLower(helper.MD5Hash(content))

	oldSign := postData["sign"].(string)
	if oldSign != sign {
		fmt.Printf("old sign=%s, new state=%s", oldSign, sign)
		helper.InfoLog("%s订单号签名不对, old sign=%s, new state=%s, content=%s ", orderId, oldSign, sign, content)
		return params, errors.New(helper.SignValidErr)
	}

	if returnCode, ok := postData["status"].(string); ok {
		//params.OrderStatus = strconv.Itoa(returnCode)
		params.OrderStatus = returnCode
	}

	params.MrchantOrderNo = orderId

	return params, nil
}
func (that *thirdEpay) DepositPay4zCallBack(fctx *fasthttp.RequestCtx) (Pay4zCallBack, error) {
	params := Pay4zCallBack{}
	var postData = map[string]interface{}{}
	err := json.Unmarshal(fctx.PostBody(), &postData)
	if err != nil {
		return params, err
	}
	orderId := postData["merchantOrderNo"].(string)
	//query := "select * from tbl_deposit where id=" + orderId
	query := fmt.Sprintf("select * from tbl_deposit where id='%s'", orderId)
	order := TblDeposit{}
	err = meta.MerchantDB.Get(&order, query)
	if err != nil {
		return params, err
	}
	if order.State == DepositSuccess || order.State == DepositCancelled || order.State == DepositRepairSuccess {
		err = fmt.Errorf("duplicated deposite notify: [%d]", order.State)
		helper.InfoLog("[DepositCallBack:order.State]:%s", err.Error())
		fctx.SetBody([]byte(`success`))
		return params, err
	}

	aaaa := postData["amount"].(float64) / 100

	params.Amount = fmt.Sprintf("%f", aaaa)
	err = compareAmount(params.Amount, order.Amount, 1)
	if err != nil {
		helper.InfoLog("compare amount error: [err: %v, req: %s, origin: %s]", err, params.Amount, order.Amount)
		helper.InfoLog("[DepositCallBack:compareAmount]:%s", err.Error())
		fctx.SetBody([]byte(`failed`))
		return params, err
	}

	keyy := ""
	query = "select app_key from tbl_pay_factory where fid=" + order.Fid
	err = meta.MerchantDB.Get(&keyy, query)
	if err != nil {
		return params, err
	}

	//	delete(postData, "attach")
	//	delete(postData, "real_cpf")
	//	delete(postData, "end_id")
	content := Pay4zSign(postData, keyy, "sign")

	// 进行 MD5 运算并转换为小写
	sign := strings.ToLower(helper.MD5Hash(content))

	oldSign := postData["sign"].(string)
	if oldSign != sign {
		fmt.Printf("old sign=%s, new state=%s", oldSign, sign)
		helper.InfoLog("%s订单号签名不对, old sign=%s, new state=%s, content=%s ", orderId, oldSign, sign, content)
		return params, errors.New(helper.SignValidErr)
	}

	if returnCode, ok := postData["status"].(string); ok {
		//params.OrderStatus = strconv.Itoa(returnCode)
		params.OrderStatus = returnCode
	}

	params.MrchantOrderNo = orderId

	return params, nil
}

func (that *thirdEpay) DepositCepayCallBack(fctx *fasthttp.RequestCtx) (EpayCallBack, error) {
	params := EpayCallBack{}
	var postData = map[string]interface{}{}
	err := json.Unmarshal(fctx.PostBody(), &postData)
	if err != nil {
		return params, err
	}
	orderId := postData["orderid"].(string)
	query := "select * from tbl_deposit where id=" + orderId
	order := TblDeposit{}
	err = meta.MerchantDB.Get(&order, query)
	if err != nil {
		return params, err
	}
	if order.State == DepositSuccess || order.State == DepositCancelled || order.State == DepositRepairSuccess {
		err = fmt.Errorf("duplicated deposite notify: [%d]", order.State)
		helper.InfoLog("[DepositCallBack:order.State]:%s", err.Error())
		fctx.SetBody([]byte(`success`))
		return params, err
	}
	params.Amount = postData["amount"].(string)
	err = compareAmount(params.Amount, order.Amount, 1)
	if err != nil {
		helper.InfoLog("compare amount error: [err: %v, req: %s, origin: %s]", err, params.Amount, order.Amount)
		helper.InfoLog("[DepositCallBack:compareAmount]:%s", err.Error())
		fctx.SetBody([]byte(`failed`))
		return params, err
	}

	keyy := ""
	query = "select app_key from tbl_pay_factory where fid=" + order.Fid
	err = meta.MerchantDB.Get(&keyy, query)
	if err != nil {
		return params, err
	}
	delete(postData, "attach")
	delete(postData, "real_cpf")
	delete(postData, "end_id")
	content := JeepaySign(postData, keyy, "sign")
	sign := strings.ToUpper(helper.MD5Hash(content))
	oldSign := postData["sign"].(string)
	if oldSign != sign {
		fmt.Printf("old sign=%s, new state=%s", oldSign, sign)
		helper.InfoLog("%s订单号签名不对, old sign=%s, new state=%s, content=%s ", orderId, oldSign, sign, content)
		return params, errors.New(helper.SignValidErr)
	}
	if returnCode, ok := postData["returncode"].(float64); ok {
		//params.OrderStatus = strconv.Itoa(returnCode)
		params.OrderStatus = fmt.Sprintf("%.0f", returnCode)
	}
	params.MerchantOrderId = orderId

	return params, nil
}

func (that *thirdEpay) Withdraw(amount, orderNo, accountNo, uid, pixId string, p TblPayFactory) error {

	var (
		accountType = int64(0)
	)

	err := withdrawEpayOrder(accountType, amount, accountNo, uid, pixId, "CPF", orderNo, p)
	if err != nil {
		helper.InfoLog("Withdraw err:%s", err.Error())
	}

	return nil
}

func (that *thirdEpay) WithdrawCallBack(fctx *fasthttp.RequestCtx) (paymentCallbackResp, error) {

	data := paymentCallbackResp{}
	data.AppId = string(fctx.FormValue("appId"))
	data.CustId = string(fctx.FormValue("custId"))
	data.MerchantOrderId = string(fctx.FormValue("merchantOrderId"))
	data.Order = string(fctx.FormValue("order"))
	data.OrderStatus = string(fctx.FormValue("orderStatus"))
	data.Amount = string(fctx.FormValue("amount"))
	data.Sign = string(fctx.FormValue("sign"))

	content := fmt.Sprintf(`amount=%s&appId=%s&custId=%s&merchantOrderId=%s&order=%s&orderStatus=%s&key=%s`, data.Amount, data.AppId, data.CustId, data.MerchantOrderId, data.Order, data.OrderStatus, meta.TgPay.AppKey)
	sign := strings.ToUpper(helper.MD5Hash(content))
	if data.Sign != sign {
		helper.InfoLog("old sign=%s, new state=%s", data.Sign, sign)
		return data, errors.New(helper.SignValidErr)
	}
	return data, nil
}

//func (that *thirdEpay) Deposit(fctx *fasthttp.RequestCtx, username, amount, orderNo string, p TblPayFactory) (PaymentDepositResp, error) {
//	//ip := helper.FromRequest(fctx)
//
//	var (
//		iamount int64
//	)
//	//if validator.CtypeDigit(p.Mchid) {
//	//	mid, _ = strconv.ParseInt(p.Mchid, 10, 64)
//	//}
//	//if validator.CtypeDigit(p.AppId) {
//	//	appid, _ = strconv.ParseInt(p.AppId, 10, 64)
//	//}
//	//if validator.CtypeDigit(p.PayCode) {
//	//	paycode, _ = strconv.ParseInt(p.PayCode, 10, 64)
//	//}
//	if validator.CtypeDigit(amount) {
//		iamount, _ = strconv.ParseInt(amount, 10, 64)
//	}
//
//	//if p.Ty == 2 {
//	//	pr := decimal.NewFromFloat(p.PayRate)
//	//	iamount = decimal.NewFromInt(iamount).Div(pr).Mul(decimal.NewFromInt(100)).IntPart()
//	//} else {
//	//	iamount = iamount * 100
//	//}
//
//	return CreateEpayOrder(iamount, p.Mchid, p.PayCode, p.Url, p.AppKey, orderNo, username, meta.Callback, meta.WebUrl)
//}

func (that *thirdEpay) CreateEpayOrder(iamount, orderId, uid string, pay TblPayFactory) (PaymentDepositResp, error) {

	var amount int64
	if validator.CtypeDigit(iamount) {
		amount, _ = strconv.ParseInt(iamount, 10, 64)
	}
	amount = amount * 100
	resp := PaymentDepositResp{
		OrderID: orderId,
	}
	//amount := strconv.FormatInt(money, 10)
	resp.UsdtCount, _ = decimal.NewFromInt(amount).Div(decimal.NewFromInt(100)).Float64()
	//ts := time.Now().Format(time.DateTime)
	//content := fmt.Sprintf(`pay_amount=%s&pay_applydate=%s&pay_bankcode=%s&pay_callbackurl=%s&pay_memberid=%s&pay_notifyurl=%s&pay_orderid=%s&pay_userid=%s&key=%s`, fmt.Sprintf("%.2f", float64(amount)), ts, payCode, payJumpUrl, mchid, payNoticeUrl, orderId, uid, appKey)
	content := fmt.Sprintf(`amount=%d&appId=%s&backUrl=%s&countryCode=%s&currencyCode=%s&custId=%s&merchantOrderId=%s&remark=%s&type=%s&userName=%s&key=%s`, amount, pay.AppId, pay.NotifyUrl, pay.CountryCode, pay.CurrencyCode, pay.Mchid, orderId, pay.PayCode, pay.Type, uid, pay.AppKey)
	sign := strings.ToUpper(helper.MD5Hash(content))

	requestURI := fmt.Sprintf("%s", pay.Url)

	recs := map[string]interface{}{
		"amount":          amount,
		"appId":           pay.AppId,
		"backUrl":         pay.NotifyUrl,
		"countryCode":     pay.CountryCode,
		"currencyCode":    pay.CurrencyCode,
		"merchantOrderId": orderId,
		"remark":          pay.PayCode,
		"sign":            sign,
		"custId":          pay.Mchid,
		"type":            pay.Type,
		"userName":        uid,
	}
	requestBody, err := helper.JsonMarshal(recs)
	if err != nil {
		return resp, errors.New(helper.FormatErr)
	}

	client := &http.Client{}
	req, err := http.NewRequest("POST", requestURI, bytes.NewReader(requestBody))
	if err != nil {
		helper.SqlSelectErrLog("content:%s,\nsign:%s,\nrequestURI:%s,\nrequestBody:%s", content, sign, requestURI, string(requestBody))
		return resp, errors.New(helper.PayServerErr)
	}
	//req.Header.Add("Content-Type", "application/x-www-form-urlencoded; charset=utf-8")
	req.Header.Add("Content-Type", "application/json")
	res, err := client.Do(req)
	if err != nil {
		helper.SqlSelectErrLog("reserr:%s", err)
		return resp, errors.New(helper.PayServerErr)
	}
	defer res.Body.Close()

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		helper.SqlSelectErrLog("resbody:%s", string(body))
		return resp, errors.New(helper.PayServerErr)
	}
	var data depositResp
	err = json.Unmarshal(body, &data)
	if err != nil {
		helper.SqlSelectErrLog("resBody:%s,\nerr:%s", data, err)
		return resp, fmt.Errorf(helper.PayServerErr)
	}
	if data.Code != "000000" {
		helper.SqlSelectErrLog("resdata:%s", data)
		return resp, fmt.Errorf(helper.PayServerErr)
	}
	resp.Addr = data.PayContent

	return resp, nil
}

// 定义结构体
type Response struct {
	Code int     `json:"code"`
	Data PayData `json:"data"`
	Msg  string  `json:"msg"`
	Sign string  `json:"sign"`
}

type PayData struct {
	OrderState int    `json:"orderState"`
	PayData    string `json:"payData"`
	ErrMsg     string `json:"errMsg"`
}

// 定义结构体
type CePayResponse struct {
	Code int       `json:"code"`
	Data CePayData `json:"data"`
	Msg  string    `json:"msg"`
	Time string    `json:"time"`
}

type CePayData struct {
	OrderNo   string `json:"order_no"`
	PixQrcode string `json:"pix_qrcode"`
	PayUrl    string `json:"pay_url"`
}

func CreateJeePayOrder(iamount, orderId, uid string, pay TblPayFactory) (PaymentDepositResp, error) {

	var amount int64
	if validator.CtypeDigit(iamount) {
		amount, _ = strconv.ParseInt(iamount, 10, 64)
	}

	amount = amount * 100
	resp := PaymentDepositResp{
		OrderID: orderId,
	}
	mb, err := GetMemberVerifyInfo(uid)
	if err != nil {
		helper.SqlSelectErrLog("query err:%s", err)
		return resp, errors.New(helper.DBErr)
	}
	reqTime := time.Now().UnixNano()
	requestURI := fmt.Sprintf("%s", pay.Url+"/api/pay/unifiedOrder")
	params := map[string]interface{}{
		"appId":      pay.AppId,
		"amount":     amount,
		"ifCode":     pay.PayCode,
		"mchNo":      pay.Mchid,
		"mchOrderNo": orderId,
		"notifyUrl":  pay.NotifyUrl,
		"reqTime":    reqTime,
		"signType":   "MD5",
		"sign":       "",
		"cpf":        mb.Cpf,
		"userName":   mb.RealName,
	}
	content := JeepaySign(params, pay.AppKey, "sign")
	// 进行 MD5 运算并转换为大写
	signValue := strings.ToUpper(helper.MD5Hash(content))
	params["sign"] = signValue
	requestBody, err := helper.JsonMarshal(params)
	if err != nil {
		return resp, errors.New(helper.FormatErr)
	}

	client := &http.Client{}
	req, err := http.NewRequest("POST", requestURI, bytes.NewReader(requestBody))
	if err != nil {
		helper.SqlSelectErrLog("content:%s,\nsign:%s,\nrequestURI:%s,\nrequestBody:%s", content, signValue, requestURI, string(requestBody))
		return resp, errors.New(helper.PayServerErr)
	}
	req.Header.Add("Content-Type", "application/json")
	res, err := client.Do(req)
	if err != nil {
		helper.SqlSelectErrLog("reserr:%s", err)
		return resp, errors.New(helper.PayServerErr)
	}
	defer res.Body.Close()

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		helper.SqlSelectErrLog("resbody:%s", string(body))
		return resp, errors.New(helper.PayServerErr)
	}

	var resData Response
	err = json.Unmarshal(body, &resData)
	fmt.Println("resData", string(body))
	if err != nil {
		helper.SqlSelectErrLog("resBody:%s,\nerr:%s", string(body), err)
		return resp, fmt.Errorf(helper.PayServerErr)
	}

	if resData.Data.ErrMsg == "CPF_INVALID" {
		helper.SqlSelectErrLog("ErrMsg:%s", resData.Data.ErrMsg)
		return resp, fmt.Errorf(helper.CPFError)
	}

	if resData.Code != 0 || resData.Data.PayData == "" {
		helper.SqlSelectErrLog("resdatacode:%d", resData.Code)
		helper.SqlSelectErrLog("resdata:%s", resData)
		return resp, fmt.Errorf(helper.PayServerErr)
	}

	resp.Addr = resData.Data.PayData
	return resp, nil
}

func CreateBetcatPayOrder(iamount, orderId, uid string, pay TblPayFactory) (PaymentDepositResp, error) {

	var amount int64
	if validator.CtypeDigit(iamount) {
		amount, _ = strconv.ParseInt(iamount, 10, 64)
	}
	//amount = amount * 100
	resp := PaymentDepositResp{
		OrderID: orderId,
	}

	requestURI := fmt.Sprintf("%s", pay.Url+"/api/v1/payment/order/create")
	params := map[string]interface{}{
		"appId":      pay.AppId,
		"merOrderNo": orderId,
		"currency":   "BRL",
		"amount":     amount,
		"notifyUrl":  pay.NotifyUrl,
		"sign":       "",
	}

	content := JeepaySign(params, pay.AppKey, "sign")
	// 进行 MD5 运算并转换为大写

	// Step 1: 转成 UTF-8 字节数组（Go 字符串本身就是 UTF-8）
	byteData := []byte(content)
	// Step 2: SHA256 编码
	hash := sha256.Sum256(byteData)
	// Step 3: 转成 16 进制字符串
	signValue := hex.EncodeToString(hash[:])

	params["sign"] = signValue
	requestBody, err := helper.JsonMarshal(params)
	if err != nil {
		return resp, errors.New(helper.FormatErr)
	}

	client := &http.Client{}
	req, err := http.NewRequest("POST", requestURI, bytes.NewReader(requestBody))
	if err != nil {
		helper.SqlSelectErrLog("content:%s,\nsign:%s,\nrequestURI:%s,\nrequestBody:%s", content, signValue, requestURI, string(requestBody))
		return resp, errors.New(helper.PayServerErr)
	}
	req.Header.Add("Content-Type", "application/json")
	res, err := client.Do(req)
	if err != nil {
		helper.SqlSelectErrLog("reserr:%s", err)
		return resp, errors.New(helper.PayServerErr)
	}
	defer res.Body.Close()

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		helper.SqlSelectErrLog("resbody:%s", string(body))
		return resp, errors.New(helper.PayServerErr)
	}

	helper.InfoLog("CreateBetcatPayOrder respone:%s", string(body))
	var result map[string]interface{}
	err = json.Unmarshal(body, &result)
	if err != nil {
		helper.SqlSelectErrLog("CreateBetcatPayOrder Unmarshal:%s", string(body))
		return resp, errors.New(helper.PayServerErr)
	}

	if _, ok := result["code"]; ok {
		if result["code"].(float64) != 0 {
			helper.SqlSelectErrLog("code Unmarshal:%s", string(body))
			return resp, errors.New(helper.PayServerErr)
		}
	}

	// 逐级类型断言获取 url
	if dataMap, ok := result["data"].(map[string]interface{}); ok {
		if paramsMap, ok := dataMap["params"].(map[string]interface{}); ok {
			if urlStr, ok := paramsMap["url"].(string); ok {
				resp.Addr = urlStr
			}
		}
	}

	return resp, nil
}

func CreateCePayOrder(iamount, orderId, uid string, pay TblPayFactory) (PaymentDepositResp, error) {

	var amount int64
	if validator.CtypeDigit(iamount) {
		amount, _ = strconv.ParseInt(iamount, 10, 64)
	}
	//amount = amount * 100
	resp := PaymentDepositResp{
		OrderID: orderId,
	}
	reqTime := time.Now().UnixNano()
	requestURI := fmt.Sprintf("%s", pay.Url+"/api/pay/transactions/get")
	params := map[string]interface{}{
		"pay_amount":      amount,
		"pay_memberid":    pay.Mchid,
		"pay_orderid":     orderId,
		"pay_notifyurl":   pay.NotifyUrl,
		"pay_callbackurl": pay.NotifyUrl,
		"pay_applydate":   reqTime,
		"pay_md5sign":     "",
	}
	content := JeepaySign(params, pay.AppKey, "pay_md5sign")
	// 进行 MD5 运算并转换为大写
	signValue := strings.ToUpper(helper.MD5Hash(content))
	params["pay_md5sign"] = signValue
	params["pay_username"] = "Emily Mileni Varela"
	params["pay_useremail"] = "test@test.com"
	params["pay_type"] = "CPF"
	params["pay_value"] = "123456"
	requestBody, err := helper.JsonMarshal(params)
	if err != nil {
		return resp, errors.New(helper.FormatErr)
	}

	client := &http.Client{}
	req, err := http.NewRequest("POST", requestURI, bytes.NewReader(requestBody))
	if err != nil {
		helper.SqlSelectErrLog("content:%s,\nsign:%s,\nrequestURI:%s,\nrequestBody:%s", content, signValue, requestURI, string(requestBody))
		return resp, errors.New(helper.PayServerErr)
	}
	req.Header.Add("Content-Type", "application/json")
	res, err := client.Do(req)
	if err != nil {
		helper.SqlSelectErrLog("reserr:%s", err)
		return resp, errors.New(helper.PayServerErr)
	}
	defer res.Body.Close()

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		helper.SqlSelectErrLog("resbody:%s", string(body))
		return resp, errors.New(helper.PayServerErr)
	}

	var resData CePayResponse
	err = json.Unmarshal(body, &resData)
	fmt.Println("", string(body))
	fmt.Println(resData)
	if err != nil {
		helper.SqlSelectErrLog("resBody:%s,\nerr:%s", string(body), err)
		return resp, fmt.Errorf(helper.PayServerErr)
	}

	if resData.Code != 1 || resData.Data.PayUrl == "" {
		helper.SqlSelectErrLog("resdata:%s", resData)
		return resp, fmt.Errorf(helper.PayServerErr)
	}

	resp.Addr = resData.Data.PayUrl
	return resp, nil
}

func withdrawEpayOrder(accountType int64, iamount, accountNo, uid, pixId, pixType, orderId string, pay TblPayFactory) error {
	var amount int64
	if validator.CtypeDigit(iamount) {
		amount, _ = strconv.ParseInt(iamount, 10, 64)
	}
	amount = amount * 100
	content := fmt.Sprintf(`amount=%d&appId=%s&backUrl=%s&cardType=%s&countryCode=%s&cpf=%s&currencyCode=%s&custId=%s&email=%s&merchantOrderId=%s&phone=%s&remark=%s&type=%s&userName=%s&walletId=%s&key=%s`, amount, pay.AppId, pay.NotifyUrl, pixType, pay.CountryCode, accountNo, pay.CurrencyCode, pay.Mchid, "email", orderId, "phone", pay.PayCode, "PIX", uid, pixId, pay.AppKey)
	helper.InfoLog("%s", content)
	sign := strings.ToUpper(helper.MD5Hash(content))
	requestURI := fmt.Sprintf("%s", pay.Url)

	recs := map[string]interface{}{
		"amount":          amount,
		"appId":           pay.AppId,
		"backUrl":         pay.NotifyUrl,
		"cardType":        pixType,
		"countryCode":     pay.CountryCode,
		"cpf":             accountNo,
		"currencyCode":    pay.CurrencyCode,
		"custId":          pay.Mchid,
		"email":           "email",
		"merchantOrderId": orderId,
		"phone":           "phone",
		"remark":          pay.PayCode,
		"type":            "PIX",
		"userName":        uid,
		"walletId":        pixId,
		"sign":            sign,
	}
	requestBody, err := helper.JsonMarshal(recs)
	if err != nil {
		return errors.New(helper.FormatErr)
	}

	client := &http.Client{}
	req, err := http.NewRequest("POST", requestURI, bytes.NewReader(requestBody))

	if err != nil {
		return errors.New(helper.PayServerErr)
	}
	req.Header.Add("Content-Type", "application/json")

	res, err := client.Do(req)
	if err != nil {
		return errors.New(helper.PayServerErr)
	}
	defer res.Body.Close()

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return errors.New(helper.PayServerErr)
	}

	var data withdrawResp
	err = json.Unmarshal(body, &data)
	if err != nil {
		return fmt.Errorf(helper.PayServerErr)
	}

	if data.Code != "000000" {
		return fmt.Errorf(helper.PayServerErr)
	}

	return nil
}

func JeepaySign(params map[string]interface{}, key, sign string) string {
	// 提取参数名，并排除 "sign" 参数
	var keys []string
	for k, v := range params {

		value := ""
		switch v.(type) {
		case int:
			value = fmt.Sprintf("%d", v.(int))
		case int32:
			value = fmt.Sprintf("%d", v.(int32))
		case int64:
			value = fmt.Sprintf("%d", v.(int64))
		case string:
			value = v.(string)
		case float32:
			value = strconv.FormatFloat(float64(v.(float32)), 'f', -1, 32)
		case float64:
			value = strconv.FormatFloat(v.(float64), 'f', -1, 64)
		default:

		}

		if k != sign && value != "" {
			keys = append(keys, k)
		}
	}

	// 按 ASCII 按顺序排序参数名
	sort.Strings(keys)

	// 拼接参数字符串
	var stringA strings.Builder
	for i, k := range keys {
		// 拼接 key=value
		switch params[k].(type) {
		case float64:
			stringA.WriteString(fmt.Sprintf("%s=%.f", k, params[k]))
		case float32:
			stringA.WriteString(fmt.Sprintf("%s=%.f", k, params[k]))
		default:
			stringA.WriteString(fmt.Sprintf("%s=%v", k, params[k]))
		}
		//stringA.WriteString(fmt.Sprintf("%s=%v", k, params[k]))
		// 参数之间以 & 分隔
		if i < len(keys)-1 {
			stringA.WriteString("&")
		}
	}

	// 拼接 key 参数以生成最终签名字符串
	stringSignTemp := fmt.Sprintf("%s&key=%s", stringA.String(), key)

	return stringSignTemp
}
func PayU2CSign(params map[string]interface{}, key, sign string) string {
	// 提取参数名，并排除 "sign" 参数
	var keys []string
	for k, v := range params {

		value := ""
		switch v.(type) {
		case int:
			value = fmt.Sprintf("%d", v.(int))
		case int32:
			value = fmt.Sprintf("%d", v.(int32))
		case int64:
			value = fmt.Sprintf("%d", v.(int64))
		case string:
			value = v.(string)
		case float32:
			value = strconv.FormatFloat(float64(v.(float32)), 'f', -1, 32)
		case float64:
			value = strconv.FormatFloat(v.(float64), 'f', -1, 64)
		default:

		}

		if k != sign && value != "" {
			keys = append(keys, k)
		}
	}

	// 按 ASCII 按顺序排序参数名
	sort.Strings(keys)

	// 拼接参数字符串
	var stringA strings.Builder
	for i, k := range keys {
		// 拼接 key=value
		switch params[k].(type) {
		case float64:
			stringA.WriteString(fmt.Sprintf("%s=%.f", k, params[k]))
		case float32:
			stringA.WriteString(fmt.Sprintf("%s=%.f", k, params[k]))
		default:
			stringA.WriteString(fmt.Sprintf("%s=%v", k, params[k]))
		}
		//stringA.WriteString(fmt.Sprintf("%s=%v", k, params[k]))
		// 参数之间以 & 分隔
		if i < len(keys)-1 {
			stringA.WriteString("&")
		}
	}

	// 拼接 key 参数以生成最终签名字符串
	stringSignTemp := fmt.Sprintf("%s&secret=%s", stringA.String(), key)

	return stringSignTemp
}
func Pay4zSign(params map[string]interface{}, key, sign string) string {
	// 提取参数名，并排除 "sign" 参数
	var keys []string
	for k, v := range params {

		value := ""
		switch v.(type) {
		case int:
			value = fmt.Sprintf("%d", v.(int))
		case int32:
			value = fmt.Sprintf("%d", v.(int32))
		case int64:
			value = fmt.Sprintf("%d", v.(int64))
		case string:
			value = v.(string)
		case float32:
			value = strconv.FormatFloat(float64(v.(float32)), 'f', -1, 32)
		case float64:
			value = strconv.FormatFloat(v.(float64), 'f', -1, 64)
		default:

		}

		if k != sign && value != "" {
			keys = append(keys, k)
		}
	}

	// 按 ASCII 按顺序排序参数名
	sort.Strings(keys)

	// 拼接参数字符串
	var stringA strings.Builder
	for i, k := range keys {
		// 拼接 key=value
		switch params[k].(type) {
		case float64:
			stringA.WriteString(fmt.Sprintf("%s=%.f", k, params[k]))
		case float32:
			stringA.WriteString(fmt.Sprintf("%s=%.f", k, params[k]))
		default:
			stringA.WriteString(fmt.Sprintf("%s=%v", k, params[k]))
		}
		//stringA.WriteString(fmt.Sprintf("%s=%v", k, params[k]))
		// 参数之间以 & 分隔
		if i < len(keys)-1 {
			stringA.WriteString("&")
		}
	}

	// 拼接 key 参数以生成最终签名字符串
	stringSignTemp := fmt.Sprintf("%s&secret=%s", stringA.String(), key)

	return stringSignTemp
}

func CreatePay4zOrder(iamount, orderId, uid string, pay TblPayFactory) (PaymentDepositResp, error) {

	var amount int64
	if validator.CtypeDigit(iamount) {
		amount, _ = strconv.ParseInt(iamount, 10, 64)
	}
	//amount = amount * 100
	resp := PaymentDepositResp{
		OrderID: orderId,
	}

	requestURI := fmt.Sprintf("%s", pay.Url+"/api/open/flex/order/trade/add")
	params := map[string]interface{}{
		"merchantNo":      pay.AppId,
		"merchantOrderNo": orderId,
		"amount":          amount * 100, //Pay4z 金额单位：分
		"code":            "PIX",
		"currency":        "BRL",
		"content":         meta.Program,
		"clientIp":        "127.0.0.01",
		"callback":        pay.NotifyUrl,
		"sign":            "",
	}

	content := Pay4zSign(params, pay.AppKey, "sign")

	// 进行 MD5 运算并转换为小写
	signValue := strings.ToLower(helper.MD5Hash(content))

	params["sign"] = signValue
	requestBody, err := helper.JsonMarshal(params)

	if err != nil {
		return resp, errors.New(helper.FormatErr)
	}

	client := &http.Client{}
	req, err := http.NewRequest("POST", requestURI, bytes.NewReader(requestBody))
	if err != nil {
		helper.SqlSelectErrLog("content:%s,\nsign:%s,\nrequestURI:%s,\nrequestBody:%s", content, signValue, requestURI, string(requestBody))
		return resp, errors.New(helper.PayServerErr)
	}
	req.Header.Add("Content-Type", "application/json")
	res, err := client.Do(req)
	if err != nil {
		helper.SqlSelectErrLog("reserr:%s", err)
		return resp, errors.New(helper.PayServerErr)
	}
	defer res.Body.Close()

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		helper.SqlSelectErrLog("resbody:%s", string(body))
		return resp, errors.New(helper.PayServerErr)
	}

	helper.InfoLog("CreatePay4zOrder respone:%s", string(body))
	var result map[string]interface{}
	err = json.Unmarshal(body, &result)
	if err != nil {
		helper.SqlSelectErrLog("CreatePay4zOrder Unmarshal:%s", string(body))
		return resp, errors.New(helper.PayServerErr)
	}

	if _, ok := result["success"]; ok {
		if !result["success"].(bool) {
			helper.SqlSelectErrLog("code Unmarshal:%s", string(body))
			return resp, errors.New(helper.PayServerErr)
		}
	}

	// 逐级类型断言获取 url
	if dataMap, ok := result["data"].(map[string]interface{}); ok {
		if _, ok := dataMap["payInfo"]; ok {
			if urlStr, ok := dataMap["payInfo"].(string); ok {
				resp.Addr = urlStr
			}
		}

		return resp, nil
	}

	return resp, errors.New(helper.PayServerErr)
}
func CreateU2CPayOrder(iamount, orderId, uid string, pay TblPayFactory) (PaymentDepositResp, error) {

	var amount int64
	if validator.CtypeDigit(iamount) {
		amount, _ = strconv.ParseInt(iamount, 10, 64)
	}
	//amount = amount * 100
	resp := PaymentDepositResp{
		OrderID: orderId,
	}

	requestURI := fmt.Sprintf("%s", pay.Url+"/api/open/merchant/trade/create")
	params := map[string]interface{}{
		"merchantId":      pay.AppId,
		"merchantOrderNo": orderId,
		"amount":          amount * 100, //Pay4z 金额单位：分
		"payType":         "PIX_QRCODE",
		"currency":        "BRL",
		"content":         meta.Program,
		"clientIp":        "127.0.0.01",
		"callback":        pay.NotifyUrl,
		"sign":            "",
	}

	content := PayU2CSign(params, pay.AppKey, "sign")

	// 进行 MD5 运算并转换为小写
	signValue := strings.ToLower(helper.MD5Hash(content))

	params["sign"] = signValue

	// 编码成 application/x-www-form-urlencoded 格式
	formData := url.Values{}
	for k, v := range params {
		formData.Set(k, fmt.Sprintf("%v", v)) // 强制转为 string
	}

	encoded := formData.Encode()

	client := &http.Client{}
	req, err := http.NewRequest("POST", requestURI, strings.NewReader(encoded))
	if err != nil {
		helper.SqlSelectErrLog("content:%s,\nsign:%s,\nrequestURI:%s,\nrequestBody:%s", content, signValue, requestURI, encoded)
		return resp, errors.New(helper.PayServerErr)
	}

	req.Header.Set("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8")

	res, err := client.Do(req)
	if err != nil {
		helper.SqlSelectErrLog("reserr:%s", err)
		return resp, errors.New(helper.PayServerErr)
	}
	defer res.Body.Close()

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		helper.SqlSelectErrLog("resbody:%s", string(body))
		return resp, errors.New(helper.PayServerErr)
	}

	helper.InfoLog("CreateU2CPayOrder respone:%s", string(body))
	var result map[string]interface{}
	err = json.Unmarshal(body, &result)
	if err != nil {
		helper.SqlSelectErrLog("CreateU2CPayOrder Unmarshal:%s", string(body))
		return resp, errors.New(helper.PayServerErr)
	}

	if _, ok := result["success"]; ok {
		if !result["success"].(bool) {
			helper.SqlSelectErrLog("code Unmarshal:%s", string(body))
			return resp, errors.New(helper.PayServerErr)
		}
	}

	// 逐级类型断言获取 url
	if dataMap, ok := result["data"].(map[string]interface{}); ok {
		if _, ok := dataMap["payUrl"]; ok {
			if urlStr, ok := dataMap["payUrl"].(string); ok {
				resp.Addr = urlStr
			}
		}

		return resp, nil
	}

	return resp, errors.New(helper.PayServerErr)
}
